

package com.soso.j.spider.service.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.soso.core.memcache.api.AsyncCacheService;
import com.soso.core.memcache.api.SyncCacheService;
import com.soso.core.service.CacheService;
import com.soso.core.util.other.ArrayUtil;
import com.soso.core.util.other.StrUtil;
import com.soso.j.spider.memcache.api.impl.AsyncCacheServiceImpl;
import com.soso.j.spider.memcache.api.impl.MemCache;
import com.soso.j.spider.memcache.api.impl.SyncCacheServiceImpl;

public class CacheServiceImpl implements CacheService {
	private static final Log log = LogFactory.getLog(CacheServiceImpl.class);
	
	public static int CACHE_SIZE_LIMIT = 1000000; 
	private static final long LOCAL_CACHE_TTL = 5000;
	private static final String RESET_DATE_KEY = "cacheResetDate";
	
	private long localCacheTime;
	private int localHits;
	private int cacheHits;
	private MemCache memCache;

	public CacheServiceImpl() {
		memCache=MemCache.getInstance();
        localCacheTime = System.currentTimeMillis();
	}
	
	@Override
	public void resetLocalCache() {
		if (System.currentTimeMillis() - localCacheTime > LOCAL_CACHE_TTL) {
			memCache.clear(); 
	        localCacheTime = System.currentTimeMillis();
		}
	}

	@Override
	public void clear() {
		memCache.clear();
		put(RESET_DATE_KEY, new Date());
	}

	@Override
	public boolean containsKey(Object key) {
		return memCache.containsKey(key);
	}

	@Override
	public boolean containsValue(Object arg0) {
		log.error("containsValue(Object arg0) not implemented");		
		return false;
	}

	@SuppressWarnings("unchecked")
	@Override
	public Set entrySet() {
		log.error("entrySet() not implemented");		
		return null;
	}

	@Override
	public Object get(Object key) {
		if (memCache.containsKey(key)) {
			localHits++;
			return memCache.get(key);
		}
		return null;
	}

	@Override
	public boolean isEmpty() {
		log.error("isEmpty() not implemented");		
		return false;
	}

	@SuppressWarnings("unchecked")
	@Override
	public Set keySet() {
		log.error("keySet() not implemented");		
		return null;
	}

	@Override
	public Object put(Object key, Object value) {
		return memCache.put(key, value);
	}

	@Override
	public Object remove(Object key) {
		return memCache.remove(key);
	}

	@Override
	public int size() {
		log.error("size() not implemented");		
		return 0;
	}

	@SuppressWarnings("unchecked")
	@Override
	public Collection values() {
		log.error("values() not implemented");		
		return null;
	}

	@Override
	public int getLocalHits() {
		return localHits;
	}

	public int getCacheHits() {
		return cacheHits;
	}

	@Override
	public byte[] getBlob(String key) {
		String chunkList = (String)get(key);
		if (chunkList != null) {
			List<byte[]> data = new ArrayList<byte[]>();
			int size = 0;
			for (String chunkKey : StrUtil.fromCSV(chunkList)) {
				byte[] chunk = (byte[])get(chunkKey);
				if (chunk == null) {
					return null;
				}
				data.add(chunk);
				size += chunk.length;
			}
			return ArrayUtil.packChunks(data);
		}
		return null;
	}

	@Override
	public void putBlob(String key, byte[] data) {
		List<String> chunkList = new ArrayList<String>();
		List<byte[]> chunks = ArrayUtil.makeChunks(data, CACHE_SIZE_LIMIT);
		int i = 0;
		for (byte[] chunk : chunks) {
			String chunkKey = key + String.valueOf(i);
			put(chunkKey, chunk);
			chunkList.add(chunkKey);
			i++;
		}
		put(key, StrUtil.toCSV(chunkList));
	}

	@Override
	public Date getResetDate() {
		return (Date)get(RESET_DATE_KEY);
	}

	@Override
	public AsyncCacheService getAsyncCacheService() {
		AsyncCacheService asyncCacheService = new AsyncCacheServiceImpl();
		return asyncCacheService;
	}

	@Override
	public SyncCacheService getSyncCacheService() {
		SyncCacheService syncCacheService=new SyncCacheServiceImpl();
		return syncCacheService;
	}

	@Override
	public void putAll(Map<? extends Object, ? extends Object> m) {
		log.error("putAll(Map<? extends Object, ? extends Object> m) not implemented");
	}

}
